package com.bestcem.xm.deliver.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.lang.ObjectId;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.util.IoUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bestcem.bp.xm.user.grpc.v1.services.GroupNode;
import com.bestcem.xm.common.core.exception.BusinessException;
import com.bestcem.xm.common.core.oss.enums.OssPathEnum;
import com.bestcem.xm.common.core.uitls.DynamicEasyExcelImportUtil;
import com.bestcem.xm.common.core.uitls.ExcelExportUtil;
import com.bestcem.xm.common.core.uitls.SignUtil;
import com.bestcem.xm.common.core.uitls.StringUtil;
import com.bestcem.xm.component.mybatis.service.impl.XmServiceImpl;
import com.bestcem.xm.component.security.context.SecurityContextHolder;
import com.bestcem.xm.componet.filestorage.service.StorageService;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.deliver.controller.v2.param.GetCustomlinkPageParam;
import com.bestcem.xm.deliver.controller.v2.param.GetDeliverextparamsPageParam;
import com.bestcem.xm.deliver.controller.v2.vo.AllDeliverDeliverPageVo;
import com.bestcem.xm.deliver.controller.v2.vo.DeliverCustomLinkExcelVo;
import com.bestcem.xm.deliver.controller.v2.vo.DeliverCustomLinkPageVo;
import com.bestcem.xm.deliver.controller.v2.vo.DeliverDeliverTempVo;
import com.bestcem.xm.deliver.controller.vo.DeliverCustomLinkVo;
import com.bestcem.xm.deliver.controller.vo.ExcelCustomLinkVo;
import com.bestcem.xm.deliver.entity.*;
import com.bestcem.xm.deliver.grpc.client.*;
import com.bestcem.xm.deliver.grpc.client.dto.AwardDto;
import com.bestcem.xm.deliver.grpc.client.dto.OrgInfoDto;
import com.bestcem.xm.deliver.mapper.*;
import com.bestcem.xm.deliver.mq.dto.CreateColumnsDto;
import com.bestcem.xm.deliver.mq.dto.CustomDeliverLinkMessageDto;
import com.bestcem.xm.deliver.mq.send.biz.DeliverMessageSendService;
import com.bestcem.xm.deliver.service.DeliverCustomLinkService;
import com.bestcem.xm.deliver.service.DeliverDeliverExtParamsService;
import com.bestcem.xm.deliver.service.DeliverDeliverService;
import com.bestcem.xm.deliver.service.ServiceSequenceService;
import com.bestcem.xm.deliver.util.CommonUtil;
import com.bestcem.xm.deliver.util.ZipUtil;
import com.bestcem.xm.openplatform.grpc.v1.services.ExtParam;
import com.bestcem.xm.openplatform.grpc.v1.services.ExtParamEnumManage;
import com.bestcem.xm.openplatform.grpc.v1.services.ExtParamStatus;
import com.bestcem.xm.openplatform.grpc.v1.services.FunctionOption;
import com.bestcem.xm.qdes.grpc.v1.services.Project;
import com.bestcem.xm.qdes.grpc.v1.services.ProjectNoDefault;
import com.google.protobuf.StringValue;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.bestcem.xm.deliver.enums.DeliverExtParamsStatusEnum.DELIVEREXTPARAMS_STATUS_START;
import static com.bestcem.xm.deliver.enums.DeliverExtParamsTypeEnum.DELIVEREXTPARAMS_DELIVER_EXTPARAM_TYPE_CUSTOM;
import static com.bestcem.xm.deliver.enums.DeliverExtParamsTypeEnum.DELIVEREXTPARAMS_DELIVER_EXTPARAM_TYPE_GENERAL;
import static com.bestcem.xm.deliver.enums.DeliverStatusEnum.DELIVER_STATUS_DELETE;
import static com.bestcem.xm.deliver.enums.DeliverStatusEnum.DELIVER_STATUS_FINISH;
import static com.bestcem.xm.deliver.enums.DeliverTtypeEnum.DELIVER_TTYPE_CUSTOM_LINK;
import static com.bestcem.xm.deliver.enums.RespondentStatusEnum.RESPONDENT_STATUS_FINISH;
import static com.bestcem.xm.deliver.grpc.v1.services.CustomLinkStatus.CUSTOMLINK_STATUS_ACTIVATE;
import static com.bestcem.xm.deliver.grpc.v1.services.CustomLinkTtype.CUSTOMLINK_TTYPE_GLOBAL;
import static com.bestcem.xm.deliver.grpc.v1.services.CustomLinkTtype.CUSTOMLINK_TTYPE_STORE;
import static com.bestcem.xm.deliver.grpc.v1.services.DeliverAwardUseType.DELIVER_AWARD_USE_TYPE_UNUSE;
import static com.bestcem.xm.deliver.grpc.v1.services.DeliverChannel.DELIVER_CHANNEL_CUSTOM_LINK;
import static com.bestcem.xm.deliver.grpc.v1.services.DeliverExtparamsExtparamType.*;
import static com.bestcem.xm.deliver.grpc.v1.services.DeliverScenes.DELIVER_SCENES_CUSTOM_LINK;
import static com.bestcem.xm.deliver.grpc.v1.services.DeliverStatus.DELIVER_STATUS_START;
import static com.bestcem.xm.openplatform.grpc.v1.services.ExtParamDtype.*;
import static com.bestcem.xm.survey.grpc.v1.services.RespondentSource.RESPONDENT_SOURCE_CUSTOM_LINK;


/**
 * @author been
 * @description 针对表【ds_deliver_customlink】的数据库操作Service实现
 * @createDate 2022-11-07 13:49:46
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DeliverCustomLinkServiceImpl extends XmServiceImpl<DeliverCustomLinkMapper, DeliverCustomLink>
        implements DeliverCustomLinkService {

    private static final String ROOT_FILE_PATH = System.getProperty("user.dir");
    private static final String SEPARATOR = "/";

    private @NonNull DeliverDeliverExtParamsMapper deliverDeliverExtParamsMapper;
    private @NonNull DeliverDeliverMapper deliverDeliverMapper;
    private @NonNull DeliverSurveyDeliverMapper deliverSurveyDeliverMapper;
    private @NonNull DeliverExtDeliverMappingMapper deliverExtDeliverMappingMapper;
    private @NonNull DeliverCustomLinkDeliverMapper deliverCustomLinkDeliverMapper;
    private @NonNull DeliverCustomLinkMapper deliverCustomLinkMapper;
    private @NonNull DeliverSurveyExtParamsVersionMapper deliverSurveyExtParamsVersionMapper;

    private @NonNull UserGrpcClient userGrpcClient;
    private @NonNull AwardGrpcClient awardGrpcClient;
    private @NonNull QdesGrpcClient qdesGrpcClient;
    private @NonNull OpenPlatformGrpcClient openPlatformGrpcClient;
    private @NonNull SurveyGrpcClient surveyGrpcClient;

    private @NonNull RedisService redisService;
    //private @NonNull OssService ossService;
    private @NonNull StorageService storageService;

    private @NonNull DeliverDeliverService deliverDeliverService;
    private @NonNull ServiceSequenceService serviceSequenceService;
    private @NonNull DeliverMessageSendService deliverMessageSendService;
    private @NonNull DeliverDeliverExtParamsService deliverDeliverExtParamsService;

    @Value("${app.deliver.customdeliver.orgCode:gt}")
    private String orgCode;

    @Override
    public DeliverCustomLinkPageVo getCustomlinks(@ApiIgnore Page<DeliverCustomLink> page, GetCustomlinkPageParam param) {
        if (param.getSurveyId().isEmpty()) {
            throw new BusinessException("project_id required");
        }
        if (param.getDeliverId().isEmpty()) {
            throw new BusinessException("缺少deliver_id");
        }
        DeliverCustomLinkPageVo pageVo = new DeliverCustomLinkPageVo();
        pageVo.setPage(page.getCurrent());

        LambdaQueryWrapper<DeliverCustomLink> defaultWrapper = Wrappers.lambdaQuery();
        defaultWrapper.eq(DeliverCustomLink::getDeliverId, param.getDeliverId())
                .eq(DeliverCustomLink::getSurveyId, param.getSurveyId());
        if (!param.getSearch().isEmpty()) {
            defaultWrapper.like(DeliverCustomLink::getTitle, param.getSearch());
        }
        Page<DeliverCustomLink> deliverCustomLinkPage = baseMapper.selectPage(page, defaultWrapper);
        //判空
        List<DeliverCustomLink> deliverCustomLinkList = deliverCustomLinkPage.getRecords();
        if (CollUtil.isEmpty(deliverCustomLinkList)) {
            pageVo.setTotalCount(0);
            pageVo.setRows(new ArrayList<>());
            return pageVo;
        }
        List<DeliverCustomLinkVo> vos = new ArrayList<>();
        deliverCustomLinkList.forEach(a -> {
            DeliverCustomLinkVo vo = new DeliverCustomLinkVo();
            BeanUtil.copyProperties(a, vo);
            vo.setFinished(surveyGrpcClient.getDeliverRspdAmount(a.getDeliverId(), a.getGroupId() == null ? "" : a.getGroupId(), null, null,
                    RESPONDENT_STATUS_FINISH.getValue(), null, a.getSurveyId()));
            vos.add(vo);
        });
        //组装
        pageVo.setRows(vos);
        pageVo.setTotalCount(deliverCustomLinkPage.getTotal());
        return pageVo;
    }

    @Override
    public List<DeliverCustomLinkVo> getCustomlinksList(GetCustomlinkPageParam param) {
        if (param.getSurveyId().isEmpty()) {
            throw new BusinessException("project_id required");
        }
        if (param.getDeliverId().isEmpty()) {
            throw new BusinessException("缺少deliver_id");
        }
        LambdaQueryWrapper<DeliverCustomLink> defaultWrapper = Wrappers.lambdaQuery();
        defaultWrapper.eq(DeliverCustomLink::getDeliverId, param.getDeliverId())
                .eq(DeliverCustomLink::getSurveyId, param.getSurveyId());
        if (!param.getSearch().isEmpty()) {
            defaultWrapper.like(DeliverCustomLink::getTitle, param.getSearch());
        }
        List<DeliverCustomLink> linkList = baseMapper.selectList(defaultWrapper);
        List<DeliverCustomLinkVo> vos = new ArrayList<>();
        linkList.forEach(a -> {
            DeliverCustomLinkVo vo = new DeliverCustomLinkVo();
            BeanUtil.copyProperties(a, vo);
            vo.setFinished(surveyGrpcClient.getDeliverRspdAmount(a.getDeliverId(), a.getGroupId() == null ? "" : a.getGroupId(), null, null,
                    RESPONDENT_STATUS_FINISH.getValue(), null, a.getSurveyId()));
            vos.add(vo);
        });
        return vos;
    }

    @Override
    public Map<String, String> getCustomlinksDownload(String deliverId) {
        LambdaQueryWrapper<DeliverCustomLink> defaultWrapper = Wrappers.lambdaQuery();
        defaultWrapper.eq(DeliverCustomLink::getDeliverId, deliverId);
        List<DeliverCustomLink> deliverCustomLinkList = baseMapper.selectList(defaultWrapper);
        List<DeliverCustomLinkExcelVo> deliverCustomLinkExcelVoList = new ArrayList<>();
        deliverCustomLinkList.forEach(e -> {
            DeliverCustomLinkExcelVo deliverCustomLinkExcelVo = new DeliverCustomLinkExcelVo();
            deliverCustomLinkExcelVo.setTitle(e.getTitle());
            deliverCustomLinkExcelVo.setLink(e.getLink());
            deliverCustomLinkExcelVoList.add(deliverCustomLinkExcelVo);
        });

        return writeExcel(deliverCustomLinkExcelVoList, deliverId);
    }

    private Map<String, String> writeExcel(List<DeliverCustomLinkExcelVo> deliverCustomLinkExcelVoList, String deliverId) {
        String filename = "所有门店自定义链接.xlsx";
        // 写入文件的路径
        String path = ROOT_FILE_PATH + File.separator + StrUtil.replace(OssPathEnum.TEMP_DELIVER.getPath(), "/", File.separator);
        Map<String, String> map = new HashMap<>();
        try {
            // 判断文件是否存在, 不存在则创建
            String excelFilePath = path + File.separator + filename;
            File file = new File(excelFilePath);
            File dir = file.getParentFile();
            if (!dir.exists()) {
                // 创建文件夹
                dir.mkdirs();
            }
            // 创建文件
            file.createNewFile();
            // 向Excel中写入数据
            EasyExcel.write(excelFilePath, DeliverCustomLinkExcelVo.class)
                    .sheet("sheet1")
                    .doWrite(deliverCustomLinkExcelVoList);
            //String url = ossService.uploadSimpleFile2(file, filename, ossPath, 0, null, "", OssPathEnum.TEMP_DELIVER);
            String osspath = OssPathEnum.DELIVER.getPath() + "customlink/" + deliverId + "/";
            log.warn("waiteExcel osspath:{}", osspath);
            String url = storageService.upload(file, filename, osspath, new Dict()).getUrl();

            map.put("url", url);

        } catch (Exception e) {
            log.error("自定义链接投放下载失败", e);
        }
        return map;
    }

    @Override
    public Map<String, String> getExternalParameterTemplate(String deliverId) {
        LambdaQueryWrapper<DeliverDeliverExtParams> defaultWrapper = Wrappers.lambdaQuery();
        defaultWrapper.eq(DeliverDeliverExtParams::getDeliverId, deliverId)
                .eq(DeliverDeliverExtParams::getStatus, DELIVEREXTPARAMS_STATUS_START.getValue())
                .eq(DeliverDeliverExtParams::getDeliverExtparamType, DELIVEREXTPARAMS_DELIVER_EXTPARAM_TYPE_GENERAL.getValue());
        List<DeliverDeliverExtParams> deliverDeliverExtParamsList = deliverDeliverExtParamsMapper.selectList(defaultWrapper);
        if (deliverDeliverExtParamsList.isEmpty()) {
            throw new BusinessException("External parameters cannot be empty");
        }

        return externalParameterTemplate(deliverId, deliverDeliverExtParamsList);
    }

    @Override
    @Transactional
    public Map<String, String> saveCustomlink(JSONObject param, String baseUrl) {

        if (ObjectUtil.isEmpty(openPlatformGrpcClient.listConditionManage(param.getString("condition_no")))) {
            throw new BusinessException("资源不存在, condition_no:" + param.getString("condition_no"));
        }
        if (ObjectUtil.isEmpty(openPlatformGrpcClient.listSystemManage(param.getString("system_no")))) {
            throw new BusinessException("资源不存在, system_no:" + param.getString("system_no"));
        }
        Map<String, String> map = new HashMap<>();
        JSONArray ext_params = param.getJSONArray("ext_params");
        for (int i = 0; i < ext_params.size(); i++) {
            JSONObject ext_param = ext_params.getJSONObject(i);
            ExtParam extparam = openPlatformGrpcClient.getExtParam(ext_param.getString("extparam_id"));
            if (ObjectUtil.isEmpty(extparam) || extparam.getStatusValue() == ExtParamStatus.EXTPARAM_STATUS_DELETE_VALUE) {
                throw new BusinessException(String.format("资源不存在, 外部参数[extparam_id=%s]", ext_param.getString("extparam_id")));
            }
            if (ObjectUtil.isNotEmpty(extparam)) {
                if (!extparam.getName().equals(ext_param.getString("extparam_name"))) {
                    throw new BusinessException(String.format("资源不存在, 外部参数[extparam_name=%s]", ext_param.getString("extparam_name")));
                }
                if (extparam.getDtypeValue() != ext_param.getIntValue("extparam_type")) {
                    throw new BusinessException(String.format("资源不存在, 外部参数[extparam_type=%s]", ext_param.getString("extparam_type")));
                }
            }
        }

        // 插入deliver
        DeliverDeliver deliver = new DeliverDeliver();
        deliver.setName(param.getString("_deliver_name"));
        deliver.setOrgId(SecurityContextHolder.getOrgId());
        deliver.setCreatedId(SecurityContextHolder.getUserId());
        deliver.setTtype(DELIVER_TTYPE_CUSTOM_LINK.getValue());
        deliver.setChannel(DELIVER_CHANNEL_CUSTOM_LINK.getNumber());
        deliver.setScenes(DELIVER_SCENES_CUSTOM_LINK.getNumber());
        deliver.setStatus(DELIVER_STATUS_START.getNumber());
        deliver.setStarttime(LocalDateTime.now());
        deliver.setCode(String.valueOf(serviceSequenceService.getSequence("DELIVER", 1)));
        // 设置默认值
        if (ObjectUtil.isNotEmpty(param.getInteger("disable"))) {
            deliver.setDisable(param.getInteger("disable"));
        } else {
            deliver.setDisable(0);
        }
        if (ObjectUtil.isNotEmpty(param.getString("reason"))) {
            deliver.setReason(param.getString("reason"));
        }
        if (ObjectUtil.isNotEmpty(param.getString("finishtime"))) {
            deliver.setFinishtime(LocalDateTime.parse(param.getString("finishtime")));
        }
        if (ObjectUtil.isNotEmpty(param.getString("delay_time"))) {
            deliver.setDelayTime(param.getString("delay_time"));
        } else {
            deliver.setDelayTime("[]");
        }
        if (ObjectUtil.isNotEmpty(param.getString("delay_failed_time"))) {
            deliver.setDelayFailedTime(param.getString("delay_failed_time"));
        } else {
            deliver.setDelayFailedTime("[]");
        }
        if (ObjectUtil.isNotEmpty(param.getInteger("delay_failed_ttype"))) {
            deliver.setDelayFailedTtype(param.getInteger("delay_failed_ttype"));
        }
        if (ObjectUtil.isNotEmpty(param.getInteger("award_use_type"))) {
            deliver.setAwardUseType(param.getInteger("award_use_type"));
        } else {
            deliver.setAwardUseType(DELIVER_AWARD_USE_TYPE_UNUSE.getNumber());
        }
        if (ObjectUtil.isNotEmpty(param.getString("award_id"))) {
            deliver.setAwardId(param.getString("award_id"));
        }
        if (ObjectUtil.isNotEmpty(param.getInteger("enable_respondent"))) {
            deliver.setEnableRespondent(param.getInteger("enable_respondent"));
        } else {
            deliver.setEnableRespondent(1);
        }
        if (ObjectUtil.isNotEmpty(param.getString("deliver_time"))) {
            deliver.setDeliverTime(LocalDateTime.parse(param.getString("deliver_time")));
        }
        if (ObjectUtil.isNotEmpty(param.getString("version"))) {
            deliver.setVersion(Long.valueOf(param.getString("version")));
        }
        deliverDeliverMapper.insert(deliver);
        // 设置是容许答题到redis中
        String key = "deliver:deliver_enable_respondent" + deliver.getId();
        // 创建投放时默认是容许答题
        // 设置redis 值为”1“ 容许答题 值为”0“ 不容许答题
        redisService.set(key, deliver.getEnableRespondent());

        DeliverSurveyDeliver deliverSurveyDeliver = new DeliverSurveyDeliver();
        deliverSurveyDeliver.setDeliverId(deliver.getId());
        deliverSurveyDeliver.setSurveyId(param.getString("survey_id"));
        deliverSurveyDeliver.setOrgId(deliver.getOrgId());
        deliverSurveyDeliverMapper.insert(deliverSurveyDeliver);

        //创建ExtDeliverMapping
        DeliverExtDeliverMapping deliverExtDeliverMapping = new DeliverExtDeliverMapping();
        deliverExtDeliverMapping.setOrgId(deliver.getOrgId());
        deliverExtDeliverMapping.setSurveyId(param.getString("survey_id"));
        deliverExtDeliverMapping.setDeliverId(deliver.getId());
        deliverExtDeliverMapping.setSystemNo(param.getString("system_no"));
        deliverExtDeliverMapping.setConditionNo(param.getString("condition_no"));
        deliverExtDeliverMappingMapper.insert(deliverExtDeliverMapping);

        //创建投放外部参数表DeliverExtparams
        JSONArray ext_param = param.getJSONArray("ext_params");
        if (!ext_param.isEmpty()) {
            for (int i = 0; i < ext_param.size(); i++) {
                DeliverDeliverExtParams deliverDeliverExtParams = new DeliverDeliverExtParams();
                deliverDeliverExtParams.setOrgId(deliver.getOrgId());
                deliverDeliverExtParams.setDeliverId(deliver.getId());
                deliverDeliverExtParams.setSurveyId(param.getString("survey_id"));
                deliverDeliverExtParams.setDeliverExtparamType(ext_param.getJSONObject(i).getInteger("deliver_extparam_type"));
                deliverDeliverExtParams.setSource(ext_param.getJSONObject(i).getInteger("source"));
                deliverDeliverExtParams.setExtparamId(ext_param.getJSONObject(i).getString("extparam_id"));
                deliverDeliverExtParams.setExtparamName(ext_param.getJSONObject(i).getString("extparam_name"));
                deliverDeliverExtParams.setExtparamType(ext_param.getJSONObject(i).getInteger("extparam_type"));
                deliverDeliverExtParams.setRequireFlag(ext_param.getJSONObject(i).getBoolean("require"));
                deliverDeliverExtParams.setSurveyUnique(ext_param.getJSONObject(i).getBoolean("survey_unique"));
                deliverDeliverExtParams.setAesEncryptStr(ext_param.getJSONObject(i).getBoolean("aes_encrypt"));
                deliverDeliverExtParams.setStatus((Integer) ext_param.getJSONObject(i).getOrDefault("status", 0));
                deliverDeliverExtParams.setExtparamDesc(ext_param.getJSONObject(i).getString("extparam_desc"));
                deliverDeliverExtParams.setStore(true);
                deliverDeliverExtParams.setSurvey(true);
                deliverDeliverExtParamsMapper.insert(deliverDeliverExtParams);
            }
        }

        //创建自定义链接投放表CustomLinkDeliver
        DeliverCustomLinkDeliver deliverCustomLinkDeliver = new DeliverCustomLinkDeliver();
        deliverCustomLinkDeliver.setOrgId(deliver.getOrgId());
        deliverCustomLinkDeliver.setDeliverId(deliver.getId());
        deliverCustomLinkDeliver.setSurveyId(param.getString("survey_id"));
        deliverCustomLinkDeliver.setIsCustom(param.getBoolean("is_custom"));
        deliverCustomLinkDeliver.setReqMethod(param.getInteger("req_method"));
        deliverCustomLinkDeliver.setGeneralRule(param.getJSONObject("general_rule").toJSONString());
        deliverCustomLinkDeliver.setCustomRule(param.getString("custom_rule"));
        deliverCustomLinkDeliver.setLinkAgingType(param.getInteger("link_aging_type"));
        JSONObject link_aging_time = param.getJSONObject("link_aging_time");
        if (ObjectUtil.isNotEmpty(link_aging_time)) {
            link_aging_time.putIfAbsent("value", "");
        }
        deliverCustomLinkDeliver.setLinkAgingTime(link_aging_time.toJSONString());
        deliverCustomLinkDeliver.setParamOnlyAgingType(param.getInteger("param_only_aging_type"));
        deliverCustomLinkDeliver.setParamOnlyAgingDays(param.getInteger("param_only_aging_days"));
        deliverCustomLinkDeliver.setSignConfig("");
        deliverCustomLinkDeliver.setSignCheck(param.getBoolean("sign_check"));
        deliverCustomLinkDeliverMapper.insert(deliverCustomLinkDeliver);

        //创建自定义链接投放链接表CustomLink
        OrgInfoDto org = userGrpcClient.getOrganization(deliver.getOrgId());
        deliverDeliverService.doDefaultDeliverNameSeq(deliver.getName(), param.getString("survey_id"), DELIVER_TTYPE_CUSTOM_LINK.getValue());

        //版本控制
        handleSurveyExtparamsVersion(param.getString("survey_id"));

        //发布新增配额消息
        CreateColumnsDto dto = new CreateColumnsDto();
        dto.setProjectId(param.getString("survey_id"));
        dto.setCompanyId(SecurityContextHolder.getOrgId());
        dto.setDeliverId(deliver.getId());
        deliverMessageSendService.surveyCreateColumns(dto);

        Map<String, String> mapTemp = new HashMap<>();
        mapTemp.put("orgId", deliver.getOrgId());
        mapTemp.put("survey_id", param.getString("survey_id"));
        mapTemp.put("deliverCustomLinkDeliverId", deliverCustomLinkDeliver.getId());
        mapTemp.put("rootGroupId", org.getRootGroupId());
        mapTemp.put("baseUrl", baseUrl);
        mapTemp.put("systemNo", param.getString("system_no"));
        mapTemp.put("conditionNo", param.getString("condition_no"));
        String taskId = createCustomlinkList(mapTemp, deliver);
        map.put("id", deliver.getId());
        map.put("task_id", taskId);
        return map;
    }

    @Override
    public Map<String, String> putCustomlink(JSONObject param, String baseUrl) {
        String deliver_id = param.getString("deliver_id");
        String org_id = param.getString("org_id");
        String project_id = param.getString("survey_id");
        //更新Deliver表name字段
        deliverDeliverMapper.update(null, new LambdaUpdateWrapper<DeliverDeliver>()
                .eq(DeliverDeliver::getId, deliver_id)
                .set(DeliverDeliver::getName, param.getString("_deliver_name")));
        Map<String, String> map = new HashMap<>();
        JSONArray ext_params = param.getJSONArray("ext_params");
        for (int i = 0; i < ext_params.size(); i++) {
            JSONObject ext_param = ext_params.getJSONObject(i);
            ExtParam extparam = openPlatformGrpcClient.getExtParam(ext_param.getString("extparam_id"));
            if (ObjectUtil.isEmpty(extparam) || extparam.getStatusValue() == ExtParamStatus.EXTPARAM_STATUS_DELETE_VALUE) {
                throw new BusinessException(String.format("资源不存在, 外部参数[extparam_id=%s]", ext_param.getString("extparam_id")));
            }
            if (ObjectUtil.isNotEmpty(extparam)) {
                if (!extparam.getName().equals(ext_param.getString("extparam_name"))) {
                    throw new BusinessException(String.format("资源不存在, 外部参数[extparam_name=%s]", ext_param.getString("extparam_name")));
                }
                if (extparam.getDtypeValue() != ext_param.getIntValue("extparam_type")) {
                    throw new BusinessException(String.format("资源不存在, 外部参数[extparam_type=%s]", ext_param.getString("extparam_type")));
                }
            }
        }

        //创建投放外部参数表DeliverExtparams
        JSONArray ext_param = param.getJSONArray("ext_params");
        if (!ext_param.isEmpty()) {
            for (int i = 0; i < ext_param.size(); i++) {
                DeliverDeliverExtParams deliverDeliverExtParams = new DeliverDeliverExtParams();
                deliverDeliverExtParams.setOrgId(org_id);
                deliverDeliverExtParams.setDeliverId(deliver_id);
                deliverDeliverExtParams.setSurveyId(project_id);
                deliverDeliverExtParams.setDeliverExtparamType(ext_param.getJSONObject(i).getInteger("deliver_extparam_type"));
                deliverDeliverExtParams.setSource(ext_param.getJSONObject(i).getInteger("source"));
                deliverDeliverExtParams.setExtparamId(ext_param.getJSONObject(i).getString("extparam_id"));
                deliverDeliverExtParams.setExtparamName(ext_param.getJSONObject(i).getString("extparam_name"));
                deliverDeliverExtParams.setExtparamType(ext_param.getJSONObject(i).getInteger("extparam_type"));
                deliverDeliverExtParams.setRequireFlag(ext_param.getJSONObject(i).getBoolean("require"));
                deliverDeliverExtParams.setSurveyUnique(ext_param.getJSONObject(i).getBoolean("survey_unique"));
                deliverDeliverExtParams.setAesEncryptStr(ext_param.getJSONObject(i).getBoolean("aes_encrypt"));
                deliverDeliverExtParams.setStatus(ext_param.getJSONObject(i).getInteger("status"));
                deliverDeliverExtParams.setExtparamDesc(ext_param.getJSONObject(i).getString("extparam_desc"));
                LambdaQueryWrapper<DeliverDeliverExtParams> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(DeliverDeliverExtParams::getDeliverId, param.getString("deliver_id"))
                        .eq(DeliverDeliverExtParams::getExtparamId, ext_param.getJSONObject(i).getString("extparam_id"));
                DeliverDeliverExtParams deliverExtParams = deliverDeliverExtParamsMapper.selectOne(queryWrapper);
                if (ObjectUtil.isNotEmpty(deliverExtParams)) {
                    deliverDeliverExtParamsMapper.update(deliverDeliverExtParams, new LambdaUpdateWrapper<DeliverDeliverExtParams>()
                            .eq(DeliverDeliverExtParams::getDeliverId, param.getString("deliver_id"))
                            .eq(DeliverDeliverExtParams::getExtparamId, ext_param.getJSONObject(i).getString("extparam_id")));
                } else {
                    deliverDeliverExtParamsMapper.insert(deliverDeliverExtParams);
                }
            }
        }

        //SurveyExtParamsVersion
        handleSurveyExtparamsVersion(project_id);

        //更新自定义链接投放表CustomLinkDeliver
        DeliverCustomLinkDeliver deliverCustomLinkDeliver = new DeliverCustomLinkDeliver();
        deliverCustomLinkDeliver.setOrgId(org_id);
        deliverCustomLinkDeliver.setDeliverId(deliver_id);
        deliverCustomLinkDeliver.setSurveyId(project_id);
        deliverCustomLinkDeliver.setIsCustom(param.getBoolean("is_custom"));
        deliverCustomLinkDeliver.setReqMethod(param.getInteger("req_method"));
        deliverCustomLinkDeliver.setGeneralRule(param.getJSONObject("general_rule").toJSONString());
        deliverCustomLinkDeliver.setCustomRule(param.getString("custom_rule"));
        deliverCustomLinkDeliver.setLinkAgingType(param.getInteger("link_aging_type"));
        JSONObject link_aging_time = param.getJSONObject("link_aging_time");
        if (ObjectUtil.isNotEmpty(link_aging_time)) {
            link_aging_time.putIfAbsent("value", "");
        }
        deliverCustomLinkDeliver.setLinkAgingTime(link_aging_time.toJSONString());
        deliverCustomLinkDeliver.setParamOnlyAgingType(param.getInteger("param_only_aging_type"));
        deliverCustomLinkDeliver.setParamOnlyAgingDays(param.getInteger("param_only_aging_days"));
        deliverCustomLinkDeliver.setSignConfig("");
        deliverCustomLinkDeliver.setSignCheck(param.getBoolean("sign_check"));
        deliverCustomLinkDeliverMapper.update(deliverCustomLinkDeliver, new LambdaUpdateWrapper<DeliverCustomLinkDeliver>()
                .eq(DeliverCustomLinkDeliver::getDeliverId, param.getString("deliver_id")));

        //发布新增配额消息
        CreateColumnsDto dto = new CreateColumnsDto();
        dto.setProjectId(project_id);
        dto.setCompanyId(org_id);
        dto.setDeliverId(deliver_id);
        deliverMessageSendService.surveyCreateColumns(dto);

        map.put("id", deliver_id);
        return map;
    }

    @Override
    public Map<String, String> extParamTemplateImport(MultipartFile file, String groupId, String deliverId) {
        Map<String, String> resultMap = new HashMap<>();
        DeliverDeliver deliverDeliver = deliverDeliverMapper.selectById(deliverId);
        //JSONObject jsonObject = new JSONObject();
        //jsonObject.put("orgId", deliverDeliver.getOrgId());
        //jsonObject.put("enable", true);
        //List<OrgCustomSetting> customSettings = userGrpcClient.listOrgCustomSetting(jsonObject);
        String domain = null;
        String filename = "SurveyLink_ExternalParameter_done.xlsx";
        String path = ROOT_FILE_PATH + File.separator + StrUtil.replace(OssPathEnum.TEMP_DELIVER.getPath(), "/", File.separator);
        String qrcodPath = ROOT_FILE_PATH + File.separator + "qrcode";
        //if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(customSettings)) {
        //    domain = customSettings.get(0).getDomain();
        //}
        DeliverCustomLink deliverCustomLink = getOneCustomlinkWithNull(deliverId, groupId);
        LambdaQueryWrapper<DeliverCustomLinkDeliver> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliverCustomLinkDeliver::getDeliverId, deliverId);
        DeliverCustomLinkDeliver deliverCustomLinkDeliver = deliverCustomLinkDeliverMapper.selectOne(queryWrapper);
        String uploadFileName = file.getOriginalFilename();
        Assert.notNull(uploadFileName, "获取原始文件名失败");
        if (uploadFileName.endsWith("xlsx") || uploadFileName.endsWith("xls") || uploadFileName.endsWith("csv")) {
            //验证文件大小，不能超过20M
            if (file.getSize() > 20 * 1024 * 1024) {
                throw new BusinessException("Upload file is too large");
            }
            //查询出来当前投放的外部参数
            LambdaQueryWrapper<DeliverDeliverExtParams> queryWrapper1 = new LambdaQueryWrapper<>();
            queryWrapper1.eq(DeliverDeliverExtParams::getDeliverId, deliverId)
                    .eq(DeliverDeliverExtParams::getStatus, DELIVEREXTPARAMS_STATUS_START.getValue())
                    .eq(DeliverDeliverExtParams::getDeliverExtparamType, DELIVEREXTPARAMS_DELIVER_EXTPARAM_TYPE_GENERAL.getValue());
            List<DeliverDeliverExtParams> deliverDeliverExtParamsList = deliverDeliverExtParamsMapper.selectList(queryWrapper1);
            //投放的外部参数名称
            List<String> headersList = new ArrayList<>();
            //需要加密的外部参数名称
            List<String> aesExtList = new ArrayList<>();
            //查询出来为类型为int的外部参数名称
            List<String> intHeadersList = new ArrayList<>();
            //查询出来为类型为float 的外部参数名称
            List<String> floatHeadersList = new ArrayList<>();
            //查询出来为类型为timestramp 的外部参数名称
            List<String> timestrampHeadersList = new ArrayList<>();
            //查询出来为类型为bool 的外部参数名称
            List<String> boolHeadersList = new ArrayList<>();
            //查询出来为类型为enum 外部参数名称
            List<String> enumHeadersList = new ArrayList<>();
            //查询出来枚举值外部参数的code
            List<String> enumCodeList = new ArrayList<>();
            deliverDeliverExtParamsList.forEach(a -> {
                String name;
                if (ObjectUtil.isNull(a.getExtparamDesc())) {
                    name = a.getExtparamName();
                } else {
                    name = a.getExtparamDesc() + " | " + a.getExtparamName();
                }
                headersList.add(name);
                if (a.getAesEncryptStr()) {
                    aesExtList.add(name);
                }
                if (DELIVEREXTPARAMS_EXTPARAM_TYPE_DATA_INT.getNumber() == a.getExtparamType()) {
                    intHeadersList.add(name);
                }
                if (DELIVEREXTPARAMS_EXTPARAM_TYPE_DATA_FLOAT.getNumber() == a.getExtparamType()) {
                    floatHeadersList.add(name);
                }
                if (DELIVEREXTPARAMS_EXTPARAM_TYPE_DATA_TIMESTRAMP.getNumber() == a.getExtparamType()) {
                    timestrampHeadersList.add(name);
                }
                if (DELIVEREXTPARAMS_EXTPARAM_TYPE_DATA_BOOL.getNumber() == a.getExtparamType()) {
                    boolHeadersList.add(name);
                }
                if (DELIVEREXTPARAMS_EXTPARAM_TYPE_DATA_ENUM.getNumber() == a.getExtparamType()) {
                    enumHeadersList.add(a.getExtparamName());
                }

                List<ExtParamEnumManage> extParamEnumManageList = openPlatformGrpcClient.listExtParamEnumManage(a.getOrgId(), a.getExtparamId());
                if (extParamEnumManageList != null) {
                    extParamEnumManageList.forEach(b -> {
                        if (b.getStatus().getNumber() == 0) {
                            enumCodeList.add(b.getCode());
                        }
                    });
                }
            });

            try {
                File file1 = new File(path);
                if (!file1.exists()) {
                    file1.mkdirs();
                }
                File fileInfo = new File(path, filename);
                file.transferTo(fileInfo);
                FileInputStream fis = new FileInputStream(fileInfo);
                byte[] stream = IoUtils.toByteArray(fis);
                List<Map<String, String>> dataList = DynamicEasyExcelImportUtil.parseExcelToView(stream, 1);
                if (dataList.isEmpty()) {
                    throw new BusinessException("Upload file cannot be empty");
                }
                //验证上传的列名是否是外部参数
                //判断通过投放外部参数表查询出来的当前投放的所有外部参数，是否和上传的文件的列名称相同
                Set<String> headersSet = new HashSet<>(headersList);
                if (!headersSet.equals(dataList.get(0).keySet())) {
                    throw new BusinessException("上传的外部参数错误");
                }
                //上传类型校验是否符合格式,number类型的参数传值最大16位,超过截断。
                for (int i = 0; i < dataList.size(); i++) {
                    for (String s : intHeadersList) {
                        if (ObjectUtil.isNotEmpty(dataList.get(i).get(s))) {
                            if (!NumberUtils.isDigits(dataList.get(i).get(s))) {
                                throw new BusinessException("生成文件失败，第" + (i + 1) + "行参数格式有误");
                            } else if (dataList.get(i).get(s).length() > 16) {
                                dataList.get(i).put(s, dataList.get(i).get(s).substring(0, 16));
                            }

                        }
                    }
                    for (String s : floatHeadersList) {
                        if (ObjectUtil.isNotEmpty(dataList.get(i).get(s))) {
                            try {
                                Float.parseFloat(dataList.get(i).get(s));
                            } catch (Exception e) {
                                throw new BusinessException("生成文件失败，第" + (i + 1) + "行参数格式有误");
                            }

                            if (dataList.get(i).get(s).length() > 16) {
                                dataList.get(i).put(s, dataList.get(i).get(s).substring(0, 16));
                            }
                        }
                    }
                    for (String s : timestrampHeadersList) {
                        if (ObjectUtil.isNotEmpty(dataList.get(i).get(s))) {
                            try {
                                DateUtil.parse(dataList.get(i).get(s));
                            } catch (Exception e) {
                                throw new BusinessException("生成文件失败，第" + (i + 1) + "行参数格式有误");
                            }
                        }
                    }

                    for (String s : boolHeadersList) {
                        if (ObjectUtil.isNotEmpty(dataList.get(i).get(s))) {
                            List<String> list = new ArrayList<>();
                            list.add("0");
                            list.add("1");
                            list.add("FALSE");
                            list.add("TRUE");
                            if (!list.contains(dataList.get(i).get(s).toUpperCase())) {
                                throw new BusinessException("生成文件失败，第" + (i + 1) + "行参数格式有误");
                            }
                        }
                    }
                    for (int j = 0; j < enumHeadersList.size(); j++) {
                        if (!enumCodeList.contains(enumHeadersList.get(i))) {
                            throw new BusinessException("生成文件失败，第" + (i + 1) + "行参数格式有误");
                        }
                    }
                }
                String aesKey = openPlatformGrpcClient.listEncryptionConfig(deliverDeliver.getOrgId());
                log.error("extParamTemplateImport aesKey={}", aesKey);
                if (!aesExtList.isEmpty()) {
                    log.error("extParamTemplateImport aesExtList={}", aesExtList);
                    for (String s : aesExtList) {
                        for (Map<String, String> stringStringMap : dataList) {
                            stringStringMap.keySet().forEach(it -> {
                                if (it.equals(s)) {
                                    String aestmp = SignUtil.encryptFromString(aesKey, stringStringMap.get(s), Mode.ECB, Padding.ZeroPadding);
                                    stringStringMap.put(s, aestmp);
                                }
                            });
                        }
                    }
                }
                //根据外部参数，生成长短链接对应
                List<String> shortLinkList = new ArrayList<>();
                List<String> longLinkList = new ArrayList<>();
                //定义一个最终的外部参数集合
                List<Map<String, Object>> extParams = new ArrayList<>();
                for (Map<String, String> m : dataList) {
                    Map<String, Object> map = new HashMap<>();
                    for (String k : m.keySet()) {
                        map.put(k.split("\\|")[1].trim(), m.get(k));
                    }
                    extParams.add(map);
                }
                //拆分出链接上的system_no，condition_no，code
                for (Map<String, Object> m : extParams) {
                    String longLink = deliverCustomLink.getLink();
                    String[] params = longLink.split("\\?")[1].split("&");
                    for (String param : params) {
                        m.put(param.split("=")[0], param.split("=")[1]);
                    }
                }

                //生成短链接
                //TODO 多线程CountDownLatch,5000个分一个线程，具体多少，可以看接口other接口处理速速度
                //TODO 长链转短链，有个批量的接口，替换一下
                //生成签名
                for (Map<String, Object> m : extParams) {
                    if (ObjectUtil.isNotEmpty(deliverCustomLinkDeliver.getSignCheck()) && deliverCustomLinkDeliver.getSignCheck()) {
                        String sig = SignUtil.genSign(m, aesKey);
                        //log.error("extParamTemplateImport 循环加密map={}", m);
                        m.put("sig", sig);
                    }
                    StringBuilder url = new StringBuilder(deliverCustomLink.getLink().split("\\?")[0] + "/?");
                    for (Map.Entry<String, Object> entry : m.entrySet()) {
                        url.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue().toString(), "UTF-8"));
                        url.append("&");
                    }
                    String longLink = StringUtils.substringBeforeLast(url.toString(), "&");
                    if (longLink.endsWith("&")) {
                        longLink = StringUtils.substringBeforeLast(longLink, "&");
                    }
                    shortLinkList.add(deliverDeliverService.getSurveyDwzLink(longLink, domain));
                    longLinkList.add(longLink);
                }
                List<ExcelCustomLinkVo> excelCustomLinkVoList = new ArrayList<>();
                for (int i = 0; i < shortLinkList.size(); i++) {
                    ExcelCustomLinkVo excelCustomLinkVo = new ExcelCustomLinkVo();
                    excelCustomLinkVo.setShortLink(shortLinkList.get(i));
                    excelCustomLinkVo.setLongLink(longLinkList.get(i));
                    excelCustomLinkVoList.add(excelCustomLinkVo);
                }

                String customLinkFilePath = path + filename;
                fis.close();
                fileInfo.delete();
                ExcelExportUtil.createExcelStream(excelCustomLinkVoList, ExcelCustomLinkVo.class, customLinkFilePath);
                /*String filePath = ossService.getFilePrefix() + OssPathEnum.QRCODE.getPath() + deliverCustomLink.getDeliverId()
                        + SEPARATOR + deliverCustomLink.getId();*/
                String ossPath = OssPathEnum.QRCODE.getPath() + deliverCustomLink.getDeliverId()
                        + SEPARATOR + deliverCustomLink.getId() + SEPARATOR;
//                String zipPath = filePath + SEPARATOR + filename;
//                ossService.downloadFile(zipPath, customLinkFile);
                //TODO 这里也会耗时，但是没办法，可以考虑注释
                for (int i = 0; i < shortLinkList.size(); i++) {
                    //二维码图片名称
                    String fileNameQr = CommonUtil.fileNameFormat("第" + (i + 1) + "行链接二维码.png");
                    deliverDeliverService.saveMatrixImgByParam(shortLinkList.get(i), path, ossPath, fileNameQr, true);
//                    String srcUrl = deliverDeliverService.createSurveyGroupQrcodes(deliverDeliver.getOrgId(), survey.getId(), deliverDeliver.getId(), content, fileName, true);
//                    File sourceFile = new File(srcUrl);
//                    try {
//                        FileUtils.copyFile(sourceFile, new File(path + fileNameQr));
//                    } catch (IOException e) {
//                        throw new BusinessException("拷贝文件失败");
//                    }
//                    sourceFile.delete();
                }
                //生成文件，返回下载url
                String zipName;
                zipName = deliverDeliver.getName() + "_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH_mm_ss"));
                // 替换文件名中的特殊字符为“_”
                zipName = CommonUtil.fileNameFormat(zipName);
                ZipUtil.zipHutool(path, qrcodPath + File.separator + zipName + ".zip");
                File zipFile = new File(qrcodPath + File.separator + zipName + ".zip");
                //String url = ossService.uploadSimpleFile2(zipFile, zipName + ".zip", filePath, 0, null, "", OssPathEnum.DELIVER);
                log.warn("extParamTemplateImport ossPath:{}", ossPath);
                String url = storageService.upload(zipFile, zipName + ".zip", ossPath, new Dict()).getUrl();
                zipFile.delete();
                FileUtil.del(file1);
                resultMap.put("zippath", url);
            } catch (Exception e) {
                log.error("extParamTemplateImport eroor:", e);
            }
        } else {
            throw new BusinessException("Upload file format error");
        }
        return resultMap;
    }

    private DeliverCustomLink getOneCustomlinkWithNull(String deliverId, String groupId) {
        LambdaQueryWrapper<DeliverCustomLink> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliverCustomLink::getDeliverId, deliverId);
        if ("null".equals(groupId) || StringUtil.isNullOrEmpty(groupId)) {
            queryWrapper.isNull(DeliverCustomLink::getGroupId);
        } else {
            queryWrapper.eq(DeliverCustomLink::getGroupId, groupId);
        }
        return deliverCustomLinkMapper.selectOne(queryWrapper);
    }

    private void handleSurveyExtparamsVersion(String survey_id) {
        LambdaQueryWrapper<DeliverSurveyExtParamsVersion> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliverSurveyExtParamsVersion::getSurveyId, survey_id);
        queryWrapper.last("limit 1");
        DeliverSurveyExtParamsVersion surveyextparamsversion_data = deliverSurveyExtParamsVersionMapper.selectOne(queryWrapper);

        if (Objects.nonNull(surveyextparamsversion_data)) {
            Integer oldVersion = surveyextparamsversion_data.getVersion();
            DeliverSurveyExtParamsVersion update = new DeliverSurveyExtParamsVersion();
            update.setVersion(oldVersion + 1);
            update.setId(surveyextparamsversion_data.getId());
            deliverSurveyExtParamsVersionMapper.updateById(update);
        } else {
            DeliverSurveyExtParamsVersion insert = new DeliverSurveyExtParamsVersion();
            insert.setVersion(1);
            insert.setSurveyId(survey_id);
            deliverSurveyExtParamsVersionMapper.insert(insert);
        }
    }

    private String createCustomlinkList(Map<String, String> map, DeliverDeliver deliver) {
        String taskId = UUID.randomUUID().toString();
        Map<String, String> keyMap = new HashMap<>();
        //直接将awardUseType传递过来，无需通过deliverId查询deliverdeliver表获取该字段
        /*if (deliver.getAwardUseType().equals(DELIVER_AWARD_USE_TYPE_USE.getNumber())) {
            keyMap.put("awardId", deliver.getAwardId());
        }*/

        keyMap.put("system_no", map.get("systemNo"));
        keyMap.put("condition_no", map.get("conditionNo"));

        GroupNode groupTree;
        JSONObject storeLevel = new JSONObject();
        if (StringUtils.isNotEmpty(map.get("rootGroupId"))) {
            groupTree = userGrpcClient.getGroupTreeByRootGroupId(map.get("rootGroupId"), false);
            List<JSONObject> levels = deliverDeliverService.getGroupLevel(map.get("rootGroupId"));
            if (CollectionUtils.isNotEmpty(levels)) {
                storeLevel = levels.get(levels.size() - 1);
            }
            List<DeliverCustomLink> deliverCustomLinkList = new ArrayList<>();
            parseNode(deliverCustomLinkList, map, groupTree, storeLevel, keyMap, deliver);

            keyMap.remove("code");
            String link = deliverDeliverService.genSurveyLink(map, deliver.getId(), keyMap);
            DeliverCustomLink deliverCustomLink = new DeliverCustomLink();
            deliverCustomLink.setOrgId(map.get("orgId"));
            deliverCustomLink.setDeliverId(deliver.getId());
            deliverCustomLink.setSurveyId(map.get("survey_id"));
            deliverCustomLink.setCustomLinkId(map.get("deliverCustomLinkDeliverId"));
            deliverCustomLink.setRootGroupId(map.get("rootGroupId"));
            deliverCustomLink.setTtype(CUSTOMLINK_TTYPE_GLOBAL.getNumber());
            deliverCustomLink.setStatus(CUSTOMLINK_STATUS_ACTIVATE.getNumber());
            deliverCustomLink.setTitle(groupTree.getName());
            deliverCustomLink.setLink(link);
            deliverCustomLinkList.add(deliverCustomLink);

            //改成mq处理,比如5000一个mq消息，这样可以几台机器一起消费，执行投放过程
            List<List<DeliverCustomLink>> listArry = ListUtil.partition(deliverCustomLinkList, 64);

            for (List<DeliverCustomLink> sub : listArry) {
                //发送mq消息
                CustomDeliverLinkMessageDto dto = new CustomDeliverLinkMessageDto();
                dto.setDeliverCustomLinkList(sub);
                dto.setMsgTotal(listArry.size());
                dto.setTaskId(taskId);
                deliverMessageSendService.saveCustomDeliverLinkSend(dto);
            }
        }
        return taskId;
    }

    private void parseNode(List<DeliverCustomLink> deliverCustomLinkList, Map<String, String> mapTemp, GroupNode node, JSONObject storeLevel,
                           Map<String, String> keyMap, DeliverDeliver deliver) {
        if (node.getLevelId().equals(storeLevel.getString("id"))) {
            int status = CUSTOMLINK_STATUS_ACTIVATE.getNumber();
            keyMap.put("code", node.getCode());
            String link = deliverDeliverService.genSurveyLink(mapTemp, deliver.getId(), keyMap);
            DeliverCustomLink deliverCustomLink = new DeliverCustomLink();
            deliverCustomLink.setOrgId(mapTemp.get("orgId"));
            deliverCustomLink.setDeliverId(deliver.getId());
            deliverCustomLink.setSurveyId(mapTemp.get("survey_id"));
            deliverCustomLink.setCustomLinkId(mapTemp.get("deliverCustomLinkDeliverId"));
            deliverCustomLink.setRootGroupId(mapTemp.get("rootGroupId"));
            deliverCustomLink.setTtype(CUSTOMLINK_TTYPE_STORE.getNumber());
            deliverCustomLink.setGroupId(node.getId());
            deliverCustomLink.setStatus(status);
            deliverCustomLink.setTitle(node.getName());
            deliverCustomLink.setCode(node.getCode());
            deliverCustomLink.setLink(link);
            deliverCustomLinkList.add(deliverCustomLink);
        } else {
            if (CollectionUtils.isEmpty(node.getChildrenList())) {
                return;
            }
            for (GroupNode childrenNode : node.getChildrenList()) {
                parseNode(deliverCustomLinkList, mapTemp, childrenNode, storeLevel, keyMap, deliver);
            }
        }
    }

    private Map<String, String> externalParameterTemplate(String deliverId, List<DeliverDeliverExtParams> deliverDeliverExtParamsList) {
        String filename = "SurveyLink_ExternalParameter_Template.xlsx";
        // 写入文件的路径
        final String path = ROOT_FILE_PATH + File.separator + StrUtil.replace(OssPathEnum.TEMP_DELIVER.getPath(), "/", File.separator);
        Map<String, String> map = new HashMap<>();
        try {
            // 判断文件是否存在, 不存在则创建
            String excelFilePath = path + File.separator + filename;
            File file = new File(excelFilePath);
            File dir = file.getParentFile();
            if (!dir.exists()) {
                // 创建文件夹
                dir.mkdirs();
            }
            // 创建文件
            file.createNewFile();
            ArrayList<List<String>> head = new ArrayList<>();
            for (DeliverDeliverExtParams deliverDeliverExtParams : deliverDeliverExtParamsList) {
                List<String> headtemp = new ArrayList<>();
                if (ObjectUtil.isNull(deliverDeliverExtParams.getExtparamDesc())) {
                    headtemp.add(deliverDeliverExtParams.getExtparamName());
                } else {
                    headtemp.add(deliverDeliverExtParams.getExtparamDesc() + " | " + deliverDeliverExtParams.getExtparamName());
                }
                head.add(headtemp);
            }
            // 向Excel中写入数据
            EasyExcel.write(excelFilePath)
                    // 这里放入动态头
                    .head(head)
                    .sheet("sheet1")
                    .doWrite(new ArrayList<>());

            String ossPath = OssPathEnum.DELIVER.getPath() + "customlink/" + deliverId + "/";
            log.warn("externalParameterTemplate ossPath:{}", ossPath);
            //String url = ossService.uploadSimpleFile2(file, filename, ossPath, 0, null, "", OssPathEnum.TEMP_DELIVER);
            String url = storageService.upload(file, filename, ossPath, new Dict()).getUrl();

            map.put("filepath", url);
            file.delete();
        } catch (Exception e) {
            log.error("自定义链接投放模板下载失败", e);
        }
        return map;
    }

    @Override
    public AllDeliverDeliverPageVo getAllCustomdeliver(@ApiIgnore Page<DeliverDeliver> page, GetCustomlinkPageParam param, String id) {
        String orgId = SecurityContextHolder.getOrgId();
        List<DeliverDeliverTempVo> deliverDeliverTempVoList = new ArrayList<>();
        AllDeliverDeliverPageVo pageVo = new AllDeliverDeliverPageVo();
        pageVo.setPage(page.getCurrent());
        LambdaQueryWrapper<DeliverDeliver> defaultWrapper = Wrappers.lambdaQuery();
        defaultWrapper.eq(DeliverDeliver::getOrgId, orgId)
                .eq(DeliverDeliver::getTtype, DELIVER_TTYPE_CUSTOM_LINK.getValue())
                .ne(DeliverDeliver::getStatus, DELIVER_STATUS_DELETE.getValue())
                .ne(DeliverDeliver::getStatus, DELIVER_STATUS_FINISH.getValue())
                .orderByDesc(DeliverDeliver::getCreatedDt);
        if (ObjectUtil.isNotEmpty(param.getTitle())) {
            ProjectNoDefault project = ProjectNoDefault.newBuilder().setTitle(StringValue.of(param.getTitle())).build();
            List<Project> projectList = qdesGrpcClient.listProjectNoDefault(project);
            if (ObjectUtil.isNotEmpty(projectList)) {
                List<DeliverSurveyDeliver> deliverSurveyDeliverList = deliverSurveyDeliverMapper.selectList(
                        new LambdaQueryWrapper<DeliverSurveyDeliver>().in(DeliverSurveyDeliver::getSurveyId, projectList.stream().map(Project::getId).collect(Collectors.toList())));
                defaultWrapper.in(DeliverDeliver::getId, deliverSurveyDeliverList.stream().map(DeliverSurveyDeliver::getDeliverId).collect(Collectors.toList()));
            } else {
                pageVo.setTotalCount(0);
                pageVo.setRows(new ArrayList<>());
                return pageVo;
            }
        }
        Page<DeliverDeliver> deliverDeliverPage = deliverDeliverMapper.selectPage(page, defaultWrapper);
        //判空
        List<DeliverDeliver> deliverDeliverList = deliverDeliverPage.getRecords();
        if (CollUtil.isEmpty(deliverDeliverList)) {
            pageVo.setTotalCount(0);
            pageVo.setRows(new ArrayList<>());
            return pageVo;
        }
        for (DeliverDeliver a : deliverDeliverList) {
            DeliverDeliverTempVo deliverDeliverTempVo = new DeliverDeliverTempVo();
            deliverDeliverTempVo.setId(a.getId());
            deliverDeliverTempVo.setCreatedDt(a.getCreatedDt());
            deliverDeliverTempVo.setUpdatedDt(a.getUpdatedDt());
            deliverDeliverTempVo.setDeleted(a.getDeleted());
            deliverDeliverTempVo.setOrgId(a.getOrgId());
            deliverDeliverTempVo.setCode(a.getCode());
            deliverDeliverTempVo.setName(a.getName());
            deliverDeliverTempVo.setTtype(a.getTtype());
            deliverDeliverTempVo.setStatus(a.getStatus());
            deliverDeliverTempVo.setChannel(a.getChannel());
            deliverDeliverTempVo.setScenes(a.getScenes());
            deliverDeliverTempVo.setDisable(a.getDisable());
            deliverDeliverTempVo.setReason(a.getReason());
            deliverDeliverTempVo.setStarttime(a.getStarttime());
            deliverDeliverTempVo.setFinishtime(a.getFinishtime());
            deliverDeliverTempVo.setDelayTime(a.getDelayTime());
            deliverDeliverTempVo.setDelayFailedTtype(a.getDelayFailedTtype());
            deliverDeliverTempVo.setDelayFailedTime(a.getDelayFailedTime());
            deliverDeliverTempVo.setAwardUseType(a.getAwardUseType());
            deliverDeliverTempVo.setAwardId(a.getAwardId());
            deliverDeliverTempVo.setEnableRespondent(a.getEnableRespondent());
            deliverDeliverTempVo.setDeliverTime(a.getDeliverTime());
            deliverDeliverTempVo.setVersion(a.getVersion());
            deliverDeliverTempVo.setCreatedId(a.getCreatedId());
            if (ObjectUtil.isNotEmpty(a.getAwardId())) {
                AwardDto award = awardGrpcClient.getAward(a.getAwardId(), false);
                deliverDeliverTempVo.setAward(award);
            }
            Map<String, String> projectInfo = new HashMap<>();
            DeliverSurveyDeliver deliverSurveyDeliver = deliverSurveyDeliverMapper.selectOne(
                    new LambdaQueryWrapper<DeliverSurveyDeliver>()
                            .eq(DeliverSurveyDeliver::getDeliverId, a.getId()));
            if (ObjectUtil.isNotEmpty(deliverSurveyDeliver)) {
                Project project = qdesGrpcClient.getProject(deliverSurveyDeliver.getSurveyId());
                projectInfo.put("id", deliverSurveyDeliver.getSurveyId());
                projectInfo.put("title", project.getTitle());
            }
            deliverDeliverTempVo.setProjectInfo(projectInfo);
            deliverDeliverTempVoList.add(deliverDeliverTempVo);
        }
        //组装
        pageVo.setRows(deliverDeliverTempVoList);
        pageVo.setTotalCount(deliverDeliverPage.getTotal());
        return pageVo;
    }

    @Override
    public void getCLDeliver(HttpServletRequest request, HttpServletResponse response) {
        //获取请求参数
        Map<String, Object> paramMap = new HashMap<>();
        Map<String, String[]> parameterMap = request.getParameterMap();
        parameterMap.forEach((key, value) -> paramMap.put(key, Stream.of(value).collect(Collectors.joining(",", "", ""))));

        log.error("getCLDeliver paramMap=[{}]", paramMap);
        String code = (String) paramMap.get("code");
        String system_no = (String) paramMap.get("system_no");
        String condition_no = (String) paramMap.get("condition_no");
        OrgInfoDto orgInfoDto = userGrpcClient.getOrganizationByIdOrCode(null, orgCode);
        if (ObjectUtil.isEmpty(orgInfoDto)) {
            throw new BusinessException("获取公司orgId异常" + orgCode);
        }
        String orgId = orgInfoDto.getId();
        LambdaQueryWrapper<DeliverExtDeliverMapping> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliverExtDeliverMapping::getOrgId, orgId)
                .eq(DeliverExtDeliverMapping::getSystemNo, system_no)
                .eq(DeliverExtDeliverMapping::getConditionNo, condition_no);
        DeliverExtDeliverMapping deliverExtDeliverMapping = deliverExtDeliverMappingMapper.selectOne(queryWrapper);
        if (ObjectUtil.isEmpty(deliverExtDeliverMapping)) {
            throw new BusinessException("问卷已结束或投放已失效");
        }
        String deliverId = deliverExtDeliverMapping.getDeliverId();
        String surveyId = deliverExtDeliverMapping.getSurveyId();
        LambdaQueryWrapper<DeliverCustomLinkDeliver> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(DeliverCustomLinkDeliver::getDeliverId, deliverId);
        DeliverCustomLinkDeliver deliverCustomLinkDeliver = deliverCustomLinkDeliverMapper.selectOne(queryWrapper1);
        //通用规则
        String generalRule = deliverCustomLinkDeliver.getGeneralRule();
        GetDeliverextparamsPageParam param = new GetDeliverextparamsPageParam();
        param.setDeliverId(deliverId);
        param.setDeliverExtparamType(String.valueOf(DELIVEREXTPARAMS_DELIVER_EXTPARAM_TYPE_GENERAL.getValue()));
        param.setStatus(String.valueOf(DELIVEREXTPARAMS_STATUS_START.getValue()));
        List<DeliverDeliverExtParams> generalParamList = deliverDeliverExtParamsService.getDeliverextparamsList(param);

        String aesKey = openPlatformGrpcClient.listEncryptionConfig(orgId);

        //验证签名
        if (ObjectUtil.isNotEmpty(deliverCustomLinkDeliver.getSignCheck()) && deliverCustomLinkDeliver.getSignCheck()) {
            if (!SignUtil.checkSign(paramMap, aesKey, null)) {
                throw new BusinessException("invalid signature");
            }
        }
        Set<String> generalParamNameList = generalParamList.stream().map(DeliverDeliverExtParams::getExtparamName).collect(Collectors.toSet());

        Set<String> set = new HashSet<>();
        set.add("system_no");
        set.add("condition_no");
        set.add("sig");
        set.add("code");
        paramMap.keySet().removeAll(set);
        if (!CollectionUtils.containsAll(generalParamNameList, paramMap.keySet())) {
            throw new BusinessException("外部参数名称错误");
        }

        //生成链接参数
        Map<String, String> kwargsMap = new HashMap<>();
        //需要加密的外部参数名称
        Map<String, Object> checkCodeDictMap = new HashMap<>();
        //转换成对应类型数据
        Map<String, Object> generalValueMap = new HashMap<>();
        //配置的枚举参数值
        List<String> enumCodeList = new ArrayList<>();
        generalParamList.forEach(a -> {
            List<ExtParamEnumManage> extParamEnumManageList = openPlatformGrpcClient.listExtParamEnumManage(a.getOrgId(), a.getExtparamId());
            extParamEnumManageList.forEach(b -> {
                if (b.getStatus().getNumber() == 0) {
                    enumCodeList.add(b.getCode());
                }
            });

            generalValueMap.put("extparamId", a.getExtparamId());
            if (a.getRequireFlag() && ObjectUtil.isEmpty(paramMap.get(a.getExtparamName()))) {
                throw new BusinessException("缺少必要通用参数");
            }
            if (a.getSurveyUnique()) {
                checkCodeDictMap.put(a.getExtparamName(), paramMap.get(a.getExtparamName()));
            }
            if ("".equals(paramMap.get(a.getExtparamName()))) {
                kwargsMap.put(a.getExtparamName(), (String) paramMap.get(a.getExtparamName()));
                generalValueMap.put(a.getExtparamName(), "");
            } else if (ObjectUtil.isNotEmpty(paramMap.get(a.getExtparamName()))) {
                kwargsMap.put(a.getExtparamName(), (String) paramMap.get(a.getExtparamName()));
                if (a.getAesEncryptStr()) {
                    try {
                        String extParamValue = SignUtil.decryptFromString(aesKey, (String) paramMap.get(a.getExtparamName()), Mode.ECB, Padding.ZeroPadding);
                        generalValueMap.put(a.getExtparamName(), extparamsTransfer(a, extParamValue));
                    } catch (Exception e) {
                        throw new BusinessException("解密失败:" + e);
                    }
                } else {
                    generalValueMap.put(a.getExtparamName(), extparamsTransfer(a, (String) paramMap.get(a.getExtparamName())));
                }
            }
        });
        generalValueMap.put("enumCodeList", enumCodeList);
        //通用规则过滤
        if (StringUtils.isNotEmpty(generalRule) && StringUtils.isNotEmpty(JSONObject.parseObject(generalRule).getString("filters"))) {
            //通用规则校验失败
            if (!parseConditions(JSONObject.parseObject(generalRule), generalValueMap)) {
                String baseUrl = request.getScheme() + "://" + request.getServerName();
                String test = ResourceUtil.readUtf8Str("file/template/ext_params_error.html");
                ServletUtil.write(response, test.replace("{src}", baseUrl + "/s/static/images/assets/404/404_no.svg"), "text/html");
            }
        }
        //定制规则校验http请求
        if (ObjectUtil.isNotEmpty(deliverCustomLinkDeliver.getIsCustom()) && (deliverCustomLinkDeliver.getIsCustom())) {
            GetDeliverextparamsPageParam param1 = new GetDeliverextparamsPageParam();
            param1.setDeliverId(deliverId);
            param1.setDeliverExtparamType(String.valueOf(DELIVEREXTPARAMS_DELIVER_EXTPARAM_TYPE_CUSTOM.getValue()));
            param1.setStatus(String.valueOf(DELIVEREXTPARAMS_STATUS_START.getValue()));
            List<DeliverDeliverExtParams> customParamList = deliverDeliverExtParamsService.getDeliverextparamsList(param1);

            String customRule = deliverCustomLinkDeliver.getCustomRule();
            if (ObjectId.isValid(customRule)) {
                if (StringUtils.isEmpty(customRule)) {
                    throw new BusinessException("定制没有定制规则");
                }
                FunctionOption functionOption = openPlatformGrpcClient.getFunctionOption(customRule);
                if (ObjectUtil.isEmpty(functionOption) || StringUtils.isEmpty(functionOption.getApi())) {
                    throw new BusinessException("定制api为空");
                }
                customRule = functionOption.getApi();
            }
            if (customRule.startsWith("/")) {
                customRule = customRule.substring(1);
            }
            String customUrl = request.getScheme() + "://" + request.getServerName() + "/" + customRule;
            generalValueMap.put("system_no", system_no);
            generalValueMap.put("condition_no", condition_no);
            generalValueMap.put("code", code);
            JSONObject resp = aioPost(generalValueMap, customUrl);
            if (ObjectUtil.isNull(resp)) {
                throw new BusinessException("Http请求连接错误");
            }
            JSONObject respData = resp.getJSONObject("data");
            // 定制结果参数校验,并生成问卷链接
            for (DeliverDeliverExtParams deliverDeliverExtParams : customParamList) {
                String extparamName = deliverDeliverExtParams.getExtparamName();
                if (ObjectUtil.isEmpty(respData.getString(extparamName)) && deliverDeliverExtParams.getRequireFlag()) {
                    throw new BusinessException("缺少必要订制参数");
                }
                if (deliverDeliverExtParams.getAesEncryptStr()) {
                    String aestmp = SignUtil.encryptFromString(aesKey, respData.getString(extparamName), Mode.ECB, Padding.ZeroPadding);
                    kwargsMap.put(extparamName, aestmp);
                } else {
                    kwargsMap.put(extparamName, respData.getString(extparamName));
                }
            }
            // 拼接订制参数
            for (DeliverDeliverExtParams deliverDeliverExtParams : customParamList) {
                String extparamName = deliverDeliverExtParams.getExtparamName();
                if (ObjectUtil.isNotEmpty(deliverDeliverExtParams.getSurveyUnique()) && deliverDeliverExtParams.getSurveyUnique()) {
                    checkCodeDictMap.put(extparamName, kwargsMap.get(extparamName));
                }
            }
            for (String kwargsMapKey : kwargsMap.keySet()) {
                if (paramMap.containsKey(kwargsMapKey)) {
                    kwargsMap.put(kwargsMapKey, (String) paramMap.get(kwargsMapKey));
                }
            }
        }

        //连接有效期
        if (ObjectUtil.isNotEmpty(deliverCustomLinkDeliver.getLinkAgingType()) && deliverCustomLinkDeliver.getLinkAgingType() == 1 && ObjectUtil.isNotEmpty(deliverCustomLinkDeliver.getLinkAgingTime())) {
            JSONObject linkAgingTime = JSON.parseObject(deliverCustomLinkDeliver.getLinkAgingTime());
            String tType = linkAgingTime.getString("type");
            String tValue = linkAgingTime.getString("value");
            long beginTime = System.currentTimeMillis();
            if ("0".equals(tType)) {
                beginTime += Long.parseLong(tValue) * 60 * 60 * 1000;
            } else if ("1".equals(tType)) {
                beginTime += Long.parseLong(tValue) * 24 * 60 * 60 * 1000;
            }
            kwargsMap.put("xm_link_aging_time", String.valueOf(beginTime));
        }
        //生成checkcode  # 保证有唯一性校验的链接只能产生一个seq
        if (ObjectUtil.isNotEmpty(checkCodeDictMap)) {
            kwargsMap.put("xm_ext_uniq", SecureUtil.md5(checkCodeDictMap.toString()));
        }

        // add code
        if (ObjectUtil.isNotEmpty(code)) {
            kwargsMap.put("code", code);
        }

        kwargsMap.put("source", String.valueOf(RESPONDENT_SOURCE_CUSTOM_LINK.getNumber()));
        kwargsMap.put("scenes", String.valueOf(DELIVER_CHANNEL_CUSTOM_LINK.getNumber()));
        kwargsMap.put("xm_custom", String.valueOf(1));
        log.info("-------kwargsMap-------" + kwargsMap);
        JSONObject surveyLink = deliverDeliverService.getSurveyLink(orgId, surveyId, deliverId, orgCode, kwargsMap);
        try {
            response.sendRedirect(surveyLink.getString("url"));
        } catch (IOException e) {
            log.error("[Deliver] 重定向失败 redirectUrl:{}", surveyLink.getString("url"), e);
        }
    }

    @Override
    public JSONObject postCLDeliver(Map<String, String> urlParamMap, JSONObject param, HttpServletRequest request) {
        //获取请求参数
        String systemNo = urlParamMap.get("system_no");
        String conditionNo = urlParamMap.get("condition_no");
        String code = urlParamMap.get("code");

        OrgInfoDto orgInfoDto = userGrpcClient.getOrganizationByIdOrCode(null, orgCode);
        if (ObjectUtil.isEmpty(orgInfoDto)) {
            throw new BusinessException("获取公司orgId异常" + orgCode);
        }
        String orgId = orgInfoDto.getId();
        LambdaQueryWrapper<DeliverExtDeliverMapping> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliverExtDeliverMapping::getOrgId, orgId)
                .eq(DeliverExtDeliverMapping::getSystemNo, systemNo)
                .eq(DeliverExtDeliverMapping::getConditionNo, conditionNo);
        DeliverExtDeliverMapping deliverExtDeliverMapping = deliverExtDeliverMappingMapper.selectOne(queryWrapper);
        if (ObjectUtil.isEmpty(deliverExtDeliverMapping)) {
            throw new BusinessException("问卷已结束或投放已失效");
        }
        String deliverId = deliverExtDeliverMapping.getDeliverId();
        String surveyId = deliverExtDeliverMapping.getSurveyId();
        LambdaQueryWrapper<DeliverCustomLinkDeliver> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.eq(DeliverCustomLinkDeliver::getDeliverId, deliverId);
        DeliverCustomLinkDeliver deliverCustomLinkDeliver = deliverCustomLinkDeliverMapper.selectOne(queryWrapper1);
        //通用规则
        String generalRule = deliverCustomLinkDeliver.getGeneralRule();
        GetDeliverextparamsPageParam pageParam = new GetDeliverextparamsPageParam();
        pageParam.setDeliverId(deliverId);
        pageParam.setDeliverExtparamType(String.valueOf(DELIVEREXTPARAMS_DELIVER_EXTPARAM_TYPE_GENERAL.getValue()));
        pageParam.setStatus(String.valueOf(DELIVEREXTPARAMS_STATUS_START.getValue()));
        List<DeliverDeliverExtParams> generalParamList = deliverDeliverExtParamsService.getDeliverextparamsList(pageParam);

        String aesKey = openPlatformGrpcClient.listEncryptionConfig(orgId);

        //验证签名
        if (ObjectUtil.isNotEmpty(deliverCustomLinkDeliver.getSignCheck()) && deliverCustomLinkDeliver.getSignCheck()) {
            if (!SignUtil.checkSign(param, aesKey, null)) {
                throw new BusinessException("invalid signature");
            }
        }
        Set<String> generalParamNameList = generalParamList.stream().map(DeliverDeliverExtParams::getExtparamName).collect(Collectors.toSet());

        Set<String> set = new HashSet<>();
        set.add("sig");
        set.add("code");
        param.keySet().removeAll(set);
        if (!CollectionUtils.containsAll(generalParamNameList, param.keySet())) {
            throw new BusinessException("外部参数名称错误");
        }

        //生成链接参数
        Map<String, String> kwargsMap = new HashMap<>();
        //需要加密的外部参数名称
        Map<String, Object> checkCodeDictMap = new HashMap<>();
        //转换成对应类型数据
        Map<String, Object> generalValueMap = new HashMap<>();
        //配置的枚举参数值
        List<String> enumCodeList = new ArrayList<>();

        generalParamList.forEach(a -> {
            List<ExtParamEnumManage> extParamEnumManageList = openPlatformGrpcClient.listExtParamEnumManage(a.getOrgId(), a.getExtparamId());
            extParamEnumManageList.forEach(b -> {
                if (b.getStatus().getNumber() == 0) {
                    enumCodeList.add(b.getCode());
                }
            });
            if (a.getRequireFlag() && ObjectUtil.isEmpty(param.getString(a.getExtparamName()))) {
                throw new BusinessException("缺少必要通用参数");
            }
            if (a.getSurveyUnique()) {
                checkCodeDictMap.put(a.getExtparamName(), param.getString(a.getExtparamName()));
            }
            if ("".equals(param.getString(a.getExtparamName()))) {
                kwargsMap.put(a.getExtparamName(), param.getString(a.getExtparamName()));
                generalValueMap.put(a.getExtparamName(), "");
            } else if (ObjectUtil.isNotEmpty(param.getString(a.getExtparamName()))) {
                kwargsMap.put(a.getExtparamName(), param.getString(a.getExtparamName()));
                if (a.getAesEncryptStr()) {
                    try {
                        String extParamValue = SignUtil.decryptFromString(aesKey, param.getString(a.getExtparamName()), Mode.ECB, Padding.ZeroPadding);
                        generalValueMap.put(a.getExtparamName(), extparamsTransfer(a, extParamValue));
                    } catch (Exception e) {
                        throw new BusinessException("解密失败:" + e);
                    }
                } else {
                    generalValueMap.put(a.getExtparamName(), extparamsTransfer(a, param.getString(a.getExtparamName())));
                }
            }
        });
        generalValueMap.put("enumCodeList", enumCodeList);
        //通用规则过滤
        if (StringUtils.isNotEmpty(generalRule) && StringUtils.isNotEmpty(JSONObject.parseObject(generalRule).getString("filters"))) {
            //通用规则校验失败
            if (!parseConditions(JSONObject.parseObject(generalRule), generalValueMap)) {
                throw new BusinessException("参数不满足通用条件");
            }
        }
        //定制规则校验http请求
        if (ObjectUtil.isNotEmpty(deliverCustomLinkDeliver.getIsCustom()) && (deliverCustomLinkDeliver.getIsCustom())) {
            GetDeliverextparamsPageParam param1 = new GetDeliverextparamsPageParam();
            param1.setDeliverId(deliverId);
            param1.setDeliverExtparamType(String.valueOf(DELIVEREXTPARAMS_DELIVER_EXTPARAM_TYPE_CUSTOM.getValue()));
            param1.setStatus(String.valueOf(DELIVEREXTPARAMS_STATUS_START.getValue()));
            List<DeliverDeliverExtParams> customParamList = deliverDeliverExtParamsService.getDeliverextparamsList(param1);

            String customRule = deliverCustomLinkDeliver.getCustomRule();
            if (ObjectId.isValid(customRule)) {
                if (StringUtils.isEmpty(customRule)) {
                    throw new BusinessException("定制没有定制规则");
                }
                FunctionOption functionOption = openPlatformGrpcClient.getFunctionOption(customRule);
                if (ObjectUtil.isEmpty(functionOption) || StringUtils.isEmpty(functionOption.getApi())) {
                    throw new BusinessException("定制api为空");
                }
                customRule = functionOption.getApi();
            }
            if (customRule.startsWith("/")) {
                customRule = customRule.substring(1);
            }
            String customUrl = request.getScheme() + "://" + request.getServerName() + "/" + customRule;

            generalValueMap.put("system_no", systemNo);
            generalValueMap.put("condition_no", conditionNo);
            generalValueMap.put("code", code);
            JSONObject resp = aioPost(generalValueMap, customUrl);
            if (ObjectUtil.isNull(resp)) {
                throw new BusinessException("Http请求连接错误");
            }
            JSONObject respData = resp.getJSONObject("data");
            // 定制结果参数校验,并生成问卷链接
            for (DeliverDeliverExtParams deliverDeliverExtParams : customParamList) {
                String extparamName = deliverDeliverExtParams.getExtparamName();
                if (ObjectUtil.isEmpty(respData.getString(extparamName)) && deliverDeliverExtParams.getRequireFlag()) {
                    throw new BusinessException("缺少必要订制参数");
                }
                if (deliverDeliverExtParams.getAesEncryptStr()) {
                    String aestmp = SignUtil.encryptFromString(aesKey, respData.getString(extparamName), Mode.ECB, Padding.ZeroPadding);
                    kwargsMap.put(extparamName, aestmp);
                } else {
                    kwargsMap.put(extparamName, respData.getString(extparamName));
                }
            }
            // 拼接订制参数
            for (DeliverDeliverExtParams deliverDeliverExtParams : customParamList) {
                String extparamName = deliverDeliverExtParams.getExtparamName();
                if (ObjectUtil.isNotEmpty(deliverDeliverExtParams.getSurveyUnique()) && deliverDeliverExtParams.getSurveyUnique()) {
                    checkCodeDictMap.put(extparamName, kwargsMap.get(extparamName));
                }
            }
            for (String kwargsMapKey : kwargsMap.keySet()) {
                if (param.containsKey(kwargsMapKey)) {
                    kwargsMap.put(kwargsMapKey, param.getString(kwargsMapKey));
                }
            }
        }

        //连接有效期
        if (ObjectUtil.isNotEmpty(deliverCustomLinkDeliver.getLinkAgingType()) && deliverCustomLinkDeliver.getLinkAgingType() == 1 && ObjectUtil.isNotEmpty(deliverCustomLinkDeliver.getLinkAgingTime())) {
            JSONObject linkAgingTime = JSON.parseObject(deliverCustomLinkDeliver.getLinkAgingTime());
            String tType = linkAgingTime.getString("type");
            String tValue = linkAgingTime.getString("value");
            long beginTime = System.currentTimeMillis();
            if ("0".equals(tType)) {
                beginTime += Long.parseLong(tValue) * 60 * 60 * 1000;
            } else if ("1".equals(tType)) {
                beginTime += Long.parseLong(tValue) * 24 * 60 * 60 * 1000;
            }
            kwargsMap.put("xm_link_aging_time", String.valueOf(beginTime));
        }
        //生成checkcode  # 保证有唯一性校验的链接只能产生一个seq
        if (ObjectUtil.isNotEmpty(checkCodeDictMap)) {
            kwargsMap.put("xm_ext_uniq", SecureUtil.md5(checkCodeDictMap.toString()));
        }

        // add code
        if (ObjectUtil.isNotEmpty(code)) {
            kwargsMap.put("code", code);
        }

        kwargsMap.put("source", String.valueOf(RESPONDENT_SOURCE_CUSTOM_LINK.getNumber()));
        kwargsMap.put("scenes", String.valueOf(DELIVER_CHANNEL_CUSTOM_LINK.getNumber()));
        kwargsMap.put("xm_custom", String.valueOf(1));

        return deliverDeliverService.getSurveyLink(orgId, surveyId, deliverId, orgCode, kwargsMap);
    }

    private JSONObject aioPost(Map<String, Object> paramMap, String url) {
        //RetrofitClient 构建x-www-form-urlencoded，一直有问题，换个原生写法
        try (HttpResponse response = HttpRequest.post(url)
                //.header(Header.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
                .body(JSON.toJSONString(paramMap))
                .execute()) {

            if (response.isOk()) {
                return JSONObject.parseObject(response.body());
            } else {
                return null;
            }
        }
    }

    private boolean parseConditions(Object obj, Map<String, Object> map) {
        String conditionsStr = JSON.toJSONString(obj);
        if (JSONUtil.isTypeJSONObject(conditionsStr)) {
            JSONObject conditions = JSONObject.parseObject(conditionsStr);
            if (conditions.containsKey("logic") || conditions.containsKey("rule")) {
                Integer logic = conditions.getInteger("logic");
                if (ObjectUtil.isEmpty(logic)) {
                    if (conditions.getOrDefault("rule", "").equals("$and")) {
                        logic = 0;
                    } else {
                        logic = 1;
                    }
                }

                List<Boolean> res = new ArrayList<>();
                JSONArray filters = conditions.getJSONArray("filters");
                for (int i = 0; i < filters.size(); i++) {
                    boolean tmp = parseConditions(filters.getJSONObject(i), map);
                    if (logic == 0 && !tmp) {
                        return false;
                    } else if (logic == 1 && tmp) {
                        return true;
                    }
                    res.add(tmp);
                }
                //0 全部条件
                if (logic == 0) {
                    return !res.contains(false);
                    //1 任一条件
                } else if (logic == 1) {
                    return res.contains(true);
                }
                return false;
            } else {
                try {
                    return customLinkConditionChecker(conditions, map);
                } catch (Exception e) {
                    log.info("条件检查错误：" + e);
                    return false;
                }
            }
        } else if (JSONUtil.isTypeJSONArray(conditionsStr)) {
            JSONArray conditionsArray = JSONArray.parseArray(conditionsStr);
            for (int j = 0; j < conditionsArray.size(); j++) {
                boolean tmp = parseConditions(conditionsArray.getJSONObject(j), map);
                if (tmp) {
                    return true;
                }
            }
            return false;
        }
        return false;
    }

    private boolean customLinkConditionChecker(JSONObject conditions, Map<String, Object> map) {
        boolean ret = false;
        String cType = conditions.getString("type");
        String keyName = conditions.getString("name");
        if (!map.containsKey(keyName)) {
            return false;
        }

        if (EXTPARAM_DTYPE_DATA_INT.getNumber() == Integer.parseInt(cType)) {
            if (NumberUtils.isDigits(String.valueOf(map.get(keyName)))) {
                ret = true;
            }
        }
        if (EXTPARAM_DTYPE_DATA_FLOAT.getNumber() == Integer.parseInt(cType)) {
            try {
                Float.parseFloat(String.valueOf(map.get(keyName)));
                ret = true;
            } catch (Exception e) {
                ret = false;
            }
        }
        if (EXTPARAM_DTYPE_DATA_STRING.getNumber() == Integer.parseInt(cType)) {
            ret = true;
        }
        if (EXTPARAM_DTYPE_DATA_TIMESTAMP.getNumber() == Integer.parseInt(cType)) {
            try {
                DateUtil.parse(String.valueOf(map.get(keyName)));
                ret = true;
            } catch (Exception e) {
                ret = false;
            }
        }
        if (EXTPARAM_DTYPE_DATA_BOOL.getNumber() == Integer.parseInt(cType)) {
            List<String> list = new ArrayList<>();
            list.add("0");
            list.add("1");
            list.add("FALSE");
            list.add("TRUE");
            if (list.contains(String.valueOf(map.get(keyName)).toUpperCase())) {
                ret = true;
            }
        }

        if (EXTPARAM_DTYPE_DATA_ENUM.getNumber() == Integer.parseInt(cType)) {
            List<String> enumCodeList = (List<String>) map.get("enumCodeList");
            if (enumCodeList.contains(map.get(keyName).toString())) {
                ret = true;
            }
        }
        return ret;
    }

    private String extparamsTransfer(DeliverDeliverExtParams deliverDeliverExtParams, String value) {
        if (DELIVEREXTPARAMS_EXTPARAM_TYPE_DATA_INT.getNumber() == deliverDeliverExtParams.getExtparamType()) {
            if (value.length() > 16) {
                value = value.substring(0, 16);
            }
        }
        if (DELIVEREXTPARAMS_EXTPARAM_TYPE_DATA_FLOAT.getNumber() == deliverDeliverExtParams.getExtparamType()) {
            if (value.length() > 16) {
                value = value.substring(0, 16);
            }
        }
        if (DELIVEREXTPARAMS_EXTPARAM_TYPE_DATA_TIMESTRAMP.getNumber() == deliverDeliverExtParams.getExtparamType()) {
            value = String.valueOf(DateUtil.parse(value));
        }
        if (DELIVEREXTPARAMS_EXTPARAM_TYPE_DATA_BOOL.getNumber() == deliverDeliverExtParams.getExtparamType()) {
            if ("1".equals(value)) {
                value = "TRUE";
            } else if ("0".equals(value)) {
                value = "FALSE";
            } else {
                throw new BusinessException("外部参数格式错误");
            }
        }
        return value;
    }
}